package com.opencee.cloud.base.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.opencee.boot.db.mybatis.service.impl.SupperServiceImpl;
import com.opencee.cloud.base.constants.BaseConstants;
import com.opencee.cloud.base.constants.BaseGrantToType;
import com.opencee.cloud.base.entity.BaseRoleEntity;
import com.opencee.cloud.base.mapper.BaseRoleMapper;
import com.opencee.cloud.base.service.IBaseRoleGrantedService;
import com.opencee.cloud.base.service.IBaseRoleService;
import com.opencee.common.exception.BaseFailException;
import com.opencee.common.utils.RedisTemplateUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 * 角色信息 服务实现类
 * </p>
 *
 * @author liuyadu
 * @since 2021-04-16
 */
@Service
public class BaseRoleServiceImpl extends SupperServiceImpl<BaseRoleMapper, BaseRoleEntity> implements IBaseRoleService {
    @Autowired
    private RedisTemplateUtil redisTemplateUtil;
    @Autowired
    private IBaseRoleGrantedService roleGrantedService;

    /**
     * 检测角色权限名称是否存在
     *
     * @param code
     * @return
     */
    @Override
    public boolean exists(String code) {
        if (StringUtils.isBlank(code)) {
            throw new BaseFailException("权限名称不能为空!");
        }
        QueryWrapper<BaseRoleEntity> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(BaseRoleEntity::getCode, code);
        return super.count(queryWrapper) > 0;
    }

    /**
     * 根据主键查询
     *
     * @param id
     * @return
     */
    @Override
    public BaseRoleEntity getById(Serializable id) {
        String key = BaseConstants.CACHE_ROLE_ID + id;
        if (redisTemplateUtil.hasKey(key)) {
            return (BaseRoleEntity) redisTemplateUtil.get(key);
        }
        BaseRoleEntity entity = super.getById(id);
        if (entity != null) {
            redisTemplateUtil.set(key, entity);
        } else {
            redisTemplateUtil.set(key, entity, 1, TimeUnit.MINUTES);
        }
        return entity;
    }

    /**
     * 保存
     *
     * @param entity
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean save(BaseRoleEntity entity) {
        if (exists(entity.getCode())) {
            throw new BaseFailException(String.format("权限名称(%s)已存在!", entity.getCode()));
        }
        entity.setAuthority(BaseGrantToType.ROLE.getValue() + BaseConstants.SEPARATOR + entity.getCode());
        entity.setDeleted(0);
        entity.setCreateTime(new Date());
        entity.setUpdateTime(entity.getCreateTime());
        boolean flag = super.save(entity);
        if (flag) {
            // 设置缓存
            String codeKey = BaseConstants.CACHE_ROLE_CODE + entity.getCode();
            String idKey = BaseConstants.CACHE_ROLE_ID + entity.getId();
            redisTemplateUtil.set(codeKey, entity);
            redisTemplateUtil.set(idKey, entity);
        }
        return flag;
    }

    /**
     * 修改
     *
     * @param entity
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateById(BaseRoleEntity entity) {
        if (entity.getId() == 1L) {
            throw new BaseFailException("超级管理员禁止修改");
        }
        BaseRoleEntity saved = getById(entity.getId());
        if (saved == null) {
            throw new BaseFailException(String.format("项目不存在!"));
        }
        if (!saved.getCode().equals(entity.getCode())) {
            // 和原来不一致重新检查唯一性
            if (exists(entity.getCode())) {
                throw new BaseFailException(String.format("权限名称(%s)已存在!", entity.getCode()));
            }
        }
        entity.setAuthority(BaseGrantToType.ROLE.getValue() + BaseConstants.SEPARATOR + entity.getCode());
        entity.setUpdateTime(new Date());
        boolean flag = super.updateById(entity);
        if (flag) {
            // 移除缓存
            String codeKey = BaseConstants.CACHE_ROLE_CODE + saved.getCode();
            String idKey = BaseConstants.CACHE_ROLE_ID + saved.getId();
            redisTemplateUtil.del(codeKey, idKey);
        }
        return flag;
    }

    /**
     * 根据角色权限名称查询角色
     *
     * @param code
     * @return
     */
    @Override
    public BaseRoleEntity getByCode(String code) {
        String key = BaseConstants.CACHE_ROLE_CODE + code;
        if (redisTemplateUtil.hasKey(key)) {
            return (BaseRoleEntity) redisTemplateUtil.get(key);
        }
        QueryWrapper<BaseRoleEntity> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().eq(BaseRoleEntity::getCode, code);
        BaseRoleEntity entity = super.getOne(queryWrapper);
        if (entity != null) {
            redisTemplateUtil.set(key, entity);
        } else {
            redisTemplateUtil.set(key, entity, 1, TimeUnit.MINUTES);
        }
        return entity;
    }

    /**
     * 根据名称或权限名称模糊查询
     *
     * @param keyword
     * @return
     */
    @Override
    public List<BaseRoleEntity> listByKeyword(String keyword) {
        QueryWrapper<BaseRoleEntity> queryWrapper = new QueryWrapper();
        queryWrapper.lambda()
                .like(BaseRoleEntity::getName, keyword)
                .or()
                .like(BaseRoleEntity::getCode, keyword);
        return super.list(queryWrapper);
    }

    /**
     * 批量id查询
     *
     * @param ids
     * @return
     */
    @Override
    public List<BaseRoleEntity> listByIds(Set<Long> ids) {
        if (ids.isEmpty()) {
            return Collections.EMPTY_LIST;
        }
        QueryWrapper<BaseRoleEntity> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().in(BaseRoleEntity::getId, ids);
        List<BaseRoleEntity> list = super.list(queryWrapper);
        return list;
    }

    /**
     * 批量code查询
     *
     * @param codes
     * @return
     */
    @Override
    public List<BaseRoleEntity> listByCodes(Set<String> codes) {
        if (codes.isEmpty()) {
            return Collections.EMPTY_LIST;
        }
        QueryWrapper<BaseRoleEntity> queryWrapper = new QueryWrapper();
        queryWrapper.lambda().in(BaseRoleEntity::getCode, codes);
        List<BaseRoleEntity> list = super.list(queryWrapper);
        return list;
    }

    /**
     * 批量id查询转map
     *
     * @param ids
     * @return
     */
    @Override
    public Map<Long, BaseRoleEntity> mapByIds(Set<Long> ids) {
        Map<Long, BaseRoleEntity> map = new HashMap<>(8);
        if (ids.isEmpty()) {
            return map;
        }
        List<BaseRoleEntity> list = listByIds(ids);
        list.forEach(t -> {
            map.put(t.getId(), t);
        });
        return map;
    }

    /**
     * 批量code查询转map
     *
     * @param codes
     * @return
     */
    @Override
    public Map<Long, BaseRoleEntity> mapByCodes(Set<String> codes) {
        Map<Long, BaseRoleEntity> map = new HashMap<>(8);
        if (codes.isEmpty()) {
            return map;
        }
        List<BaseRoleEntity> list = listByCodes(codes);
        list.forEach(t -> {
            map.put(t.getId(), t);
        });
        return map;
    }


    /**
     * 删除
     *
     * @param id
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean removeById(Serializable id) {
        if ((Long) id == 1L) {
            throw new BaseFailException("超级管理员禁止删除");
        }
        BaseRoleEntity saved = getById(id);
        if (saved == null) {
            return false;
        }
        if (roleGrantedService.hasGranted((Long) id)) {
            throw new BaseFailException("角色已被授权,无法删除");
        }
        boolean flag = super.removeById(id);
        if (flag) {
            // 级联删除
            roleGrantedService.removeByRoleId((Long) id);
            // 移除缓存
            String codeKey = BaseConstants.CACHE_ROLE_CODE + saved.getCode();
            String idKey = BaseConstants.CACHE_ROLE_ID + saved.getId();
            redisTemplateUtil.del(codeKey, idKey);
        }
        return flag;
    }
}
